今天要來學習的是 Compose 官方 Thinking in Compose 裡面的 Recomposition (重組):
在命令式(Imperative)的 UI 模型裡,為了改變 UI widget 的狀態或內容,開發者必須呼叫 widget 的 setter 函式來 update 內部的狀態或內容。 在 Compose 的世界裡,** 當有相關的資料有異動的時候,Composable function 會主動被呼叫** 也就是這個 function 被 recomposed(重新組合) 了,這時 UI widgets 會被重新繪製,大家可能會擔心會不會有大量畫面被更新,就如同 React 一樣,Compose framework 會很聰明的只 recompose 需要重置的元件,不會造成不必要的重繪(re-rendering)。
例如:ClickCounter 這個 composable 函式裡面顯示一個 Button:
@Composable
fun ClickCounter(clicks: Int, onClick: () -> Unit) {
Button(onClick = onClick) {
Text("I've been clicked $clicks times")
}
}
每次當這個 Button 被點擊時,caller 更新了 clicks 的值,Compose 呼叫 lambda 函式裡頭的 Text 函式來顯示新的 clicks 值,這樣的過程稱作 Recomposition。 而其他沒有和 clicks 相關的 composable 函式時不會被呼叫。
如果要 rescomposing 整哥 UI tree 的成本是非常高的,會使用更多的算力以及消耗電量。很幸運地,Compose 的 recomposition 是很有智慧的。
Recomposition 是輸入改變時呼叫 composable functions 的過程。發生在函式的輸入改變的時候。
Recomposition 可能會帶來一些 side-effect 而更新畫面,一下動作都是危險的 side-effects:
為了避免更新畫面的順暢度,請把耗時的工作放在背景執行。
例如,下方的程式碼會建立一個 composable 來更新 SharedPreferences 中的值。這個 composable function 不應從 SharedPreferences 本身讀取或寫入,應該把讀取或寫入的動作放在背景的 ViewModel,Application 邏輯層會適時地更新畫面。
@Composable
fun SharedPrefsToggle(
text: String,
value: Boolean,
onValueChanged: (Boolean) -> Unit
) {
Row {
Text(text)
Checkbox(checked = value, onCheckedChange = onValueChanged)
}
}
此文件會討論幾個 compose 程式的注意事項:
接下來會一一地討論這些注意事項。